package com.yungu.swift.lbs.utils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.yungu.swift.lbs.model.vo.GeoVo;
import com.yungu.swift.lbs.model.vo.RegeoVo;
import com.yungu.swift.utils.HttpUtils;
import com.yungu.swift.utils.JsonUtils;
import com.yungu.swift.utils.MapUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import static com.yungu.swift.lbs.config.NacosListener.THIRDPARTY_CONFIG;


/**
 * Description
 *
 * @author cuixiuyin
 * @date 2019/4/8
 */
@Slf4j
public class LocationUtils {


    private static double EARTH_RADIUS = 6378.137;


    /**
     * 高德 - 地理编码
     *
     * @param address
     * @return
     */
    public static GeoVo geo(String address) {
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("address", address);
        String result = HttpUtils.postResponseString("https://restapi.amap.com/v3/geocode/geo", paramsMap);
        try {
            JsonNode jsonNode = JsonUtils.readNode(result);
            int status = jsonNode.get("status").asInt();
            if (status == 1) {
                List<GeoVo> geocodes = JsonUtils.readListValue(jsonNode.get("geocodes").toString(), GeoVo.class);
                if (CollectionUtils.isNotEmpty(geocodes)) {
                    return geocodes.get(0);
                }
            }
        } catch (Exception e) {
            log.error("LocationUtils geo .result:{}", result, e);
        }
        return new GeoVo();
    }

    /**
     * 高德 - 逆地理编码 - 经纬度换成成地址信息
     *
     * @param lng
     * @param lat
     * @return
     */
    public static RegeoVo regeo(Double lng, Double lat) {
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("location", lng + "," + lat);
        String result = HttpUtils.postResponseString("http://restapi.amap.com/v3/geocode/regeo", paramsMap);
        try {
            //获取逆地理编码时，城市为空的情况，高德返回空数组，需要处理成字符
            if(result.contains("\"city\":[],")){
                result=result.replace("\"city\":[],","\"city\":\"\",");
            }
            JsonNode jsonNode = JsonUtils.readNode(result);
            int status = jsonNode.get("status").asInt();
            if (status == 1) {
//                ObjectMapper mapper = new ObjectMapper();
//                return mapper.treeToValue(jsonNode.get("regeocode"), RegeoVo.class);
                return JsonUtils.readValue(jsonNode.get("regeocode").toString(), RegeoVo.class);
            }
        } catch (Exception e) {
            log.error("LocationUtils regeo error.result:{}", result, e);
        }
        return new RegeoVo();
    }

    /**
     * 高德 - 地理/逆地理编码 - 经纬度换成成地址信息 - 批量
     *
     * @param locations
     * @return
     */

    public static Map<String, Object> getBatchPointsJson(String locations) {
        log.info("getBatchPointsJson, locations:{}", locations);
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("location", locations);
        paramsMap.put("batch", true);
        String result = HttpUtils.postResponseString("http://restapi.amap.com/v3/geocode/regeo", paramsMap);
        try {
            return JsonUtils.readValue(result, Map.class);
        } catch (IOException e) {
            log.error("LocationUtils getBatchPointsJson JsonUtils readNode error.result:{}", result);
        }
        return MapUtils.build();
    }


    /**
     * 通过经纬度获取距离(单位：米)
     *
     * @param lng1
     * @param lat1
     * @param lng2
     * @param lat2
     * @return
     */
    public static Double getDistance(double lng1, double lat1, double lng2, double lat2) {
        double radLat1 = rad(lat1);
        double radLat2 = rad(lat2);
        double a = radLat1 - radLat2;
        double b = rad(lng1) - rad(lng2);
        double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2)
                * Math.pow(Math.sin(b / 2), 2)));
        s = s * EARTH_RADIUS;
        s = Math.round(s * 10000d) / 10000d;
        s = s * 1000;
        return s;
    }

    private static double rad(double d) {
        return d * Math.PI / 180.0;
    }

    /**
     * 高德 -获取两个经纬度之间的距离
     *
     * @param originLng
     * @param originLat
     * @param areaLng
     * @param areaLat
     * @return
     */
    public static Double getDistance(String originLng, String originLat, String areaLng, String areaLat) {
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("origins", originLng + "," + originLat);
        paramsMap.put("destination", areaLng + "," + areaLat);
        String str = HttpUtils.postResponseString("http://restapi.amap.com/v3/distance", paramsMap);
        try {
            JsonNode jsonObject = JsonUtils.readNode(str);
            String status = jsonObject.get("status").asText();
            String info = jsonObject.get("info").asText();
            if (status.equals("1") && info.equals("OK")) {
                ArrayNode results = JsonUtils.readArray(jsonObject.get("results").toString());
                JsonNode object = results.get(0);
                Double distance = object.get("distance").asDouble();
                if (object.get("info") == null) {
                    return distance;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return -1d;
    }

    /**
     * 高德 - 根据起点终点经纬度获取速度最快规划路径
     *
     * @param originLng
     * @param originLat
     * @param areaLng
     * @param areaLat
     * @return
     */
    public static Map<String, Object> getDriving(String originLng, String originLat, String areaLng, String areaLat) {
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("origin", originLng + "," + originLat);
        paramsMap.put("destination", areaLng + "," + areaLat);
        paramsMap.put("extensions", "all");
        paramsMap.put("output", "JSON");
        paramsMap.put("strategy", 10);
        String str = HttpUtils.postResponseString("http://restapi.amap.com/v3/direction/driving", paramsMap);
        try {
            Map result = JsonUtils.readValue(str, Map.class);
            String status = String.valueOf(result.get("status"));
            String info = String.valueOf(result.get("info"));
            if (status.equals("1") && info.equals("OK")) {
                Map route = (Map) result.get("route");
                List paths = (List) route.get("paths");
                if(paths.size() > 0) {
                    return (Map) paths.get(0);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return MapUtils.build();
    }

    /**
     * 高德 - 调用车辆轨迹查询接口获取行驶里程（单位：米）
     *
     * @param vehicleId 司机id
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return
     */
    public static Map<String, Object> getDrivingDistance(String vehicleId, long startTime, long endTime) {
        Map<String, Object> paramsMap = MapUtils.build();
        paramsMap.put("key", THIRDPARTY_CONFIG.getGaodeKey());
        paramsMap.put("sid", THIRDPARTY_CONFIG.getGaodeSid());
        paramsMap.put("vehicleId", vehicleId);
        paramsMap.put("startTime", startTime);
        paramsMap.put("endTime", endTime);
        String str = HttpUtils.postResponseString("https://tsapi.amap.com/v1/carhailing/vehicle/track", paramsMap);
        try {
            Map<String, Object> map = JsonUtils.readValue(str, Map.class);
            String errCode = String.valueOf(map.get("errcode"));
            //1000 请求正常
            if ("10000".equals(errCode)) {
                return (Map) map.get("data");
            }
            log.info("getDrivingDistance error.errCode={}, errdetail={}", errCode, map.get("errdetail"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return MapUtils.build();
    }


}
